/* Simple utility to generate a source file containing the raw VDSO image that
 * we compile into the kernel
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

#define PAGESIZE 4096

#define die(fmt, args...) {\
    fprintf(stderr, fmt, ##args);\
    exit(EXIT_FAILURE);\
}

static void
write_header(FILE * fp)
{
    fprintf(fp, "/* This file is automatically generated by vdsogen\n");
    fprintf(fp, " * - DO NOT MODIFY -\n");
    fprintf(fp, " */\n");

    fprintf(fp, "const unsigned char vdso_raw[] __attribute__((aligned (%d))) = {", PAGESIZE);
}

static void
write_footer(FILE * fp, unsigned long total)
{
    fprintf(fp, "\n");
    fprintf(fp, "};\n");
    fprintf(fp, "const unsigned long vdso_raw_length = %ld;\n", total);
}

int main(int argc, char ** argv)
{
    int fd;
    FILE * fp_out;
    unsigned long total;

    struct stat st;

    if (argc != 3)
        die("usage: %s <vdso.so> <output.c>\n", *argv);

    fd = open(argv[1], O_RDONLY);
    if (fd == -1)
        die("failed to open %s: %s\n", argv[1], strerror(errno));

    if (fstat(fd, &st) == -1)
        die("failed to stat %s: %s\n", argv[1], strerror(errno));

    fp_out = fopen(argv[2], "w");
    if (fp_out == NULL)
        die("failed to open %s: %s\n", argv[2], strerror(errno));

    write_header(fp_out);

    for (total = 0; ; total++) {
        unsigned char byte;
        ssize_t ret;

        ret = read(fd, &byte, sizeof(unsigned char));
        if (ret == -1)
            die("failed to read %s: %s\n", argv[1], strerror(errno));

        if (ret == 0)
            break;

        if (ret != sizeof(unsigned char))
            die("read %ld bytes instead of %ld\n", ret, sizeof(unsigned char));

        fprintf(fp_out, "%s0x%02X,%s", 
            (total % 8 == 0) ? "\n    " : "",
            byte,
            (total % 8 != 7) ? " " : ""
        );
    }

    /* pad to multiple of page size */
    unsigned long rem = total & (PAGESIZE - 1);
    if (rem != 0) {
        unsigned long end = total + (PAGESIZE - rem);
        for (; total < end; total++) {
            fprintf(fp_out, "%s0x00,%s", (total % 8 == 0) ? "\n    " : "",
                    (total % 8 != 7) ? " " : "");
        }
    }

    write_footer(fp_out, total);
    fclose(fp_out);
    close(fd);

    exit(EXIT_SUCCESS);
}
